home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / httpproxy / src / net_amitcp.c < prev    next >
C/C++ Source or Header  |  1996-08-20  |  17KB  |  620 lines

  1. /*(( "Header" */
  2. /*
  3.  * $Id: net_amitcp.c,v 1.6 1996/08/11 22:25:15 mshopf Exp mshopf $
  4.  * (c) 1995-96 Matthias Hopf
  5.  *
  6.  * AmiTCP net protocol stack handler.
  7.  */
  8.  
  9. /*
  10.  * $Log: net_amitcp.c,v $
  11.  * Revision 1.6  1996/08/11  22:25:15  mshopf
  12.  * reworked debug messages.
  13.  *
  14.  * Revision 1.5  1996/07/17  16:42:42  mshopf
  15.  * added local hostname fetch.
  16.  *
  17.  * Revision 1.4  1996/06/03  04:08:19  mshopf
  18.  * added error messages.
  19.  * added hostname caching.
  20.  * added timeouts.
  21.  *
  22.  * Revision 1.3  1996/04/26  05:14:03  mshopf
  23.  * added blocking mode and rudimentary strerror.
  24.  * V0.13 alpha 5 fix.
  25.  *
  26.  * Revision 1.2  1996/04/24  17:41:16  mshopf
  27.  * some fixes.
  28.  *
  29.  * Revision 1.1  1996/04/24  03:20:13  mshopf
  30.  * Initial revision
  31.  *
  32.  */
  33.  
  34.  
  35. /*)) */
  36.  
  37. /*(( "Includes" */
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <stddef.h>
  42. #include <errno.h>
  43. #include <string.h>
  44. #include <unistd.h>
  45. #include <time.h>
  46. #include <ctype.h>
  47.  
  48. #include <sys/types.h>
  49. #include <sys/param.h>
  50. #include <sys/syslog.h>
  51. #include <sys/time.h>
  52. #include <sys/ioctl.h>
  53. #include <sys/socket.h>
  54. #include <netdb.h>
  55. #include <netinet/in.h>
  56. #include <arpa/inet.h>
  57.  
  58. #include <proto/exec.h>
  59. #include <exec/types.h>
  60.  
  61. #include "net.h"
  62. #include "debug.h"
  63.  
  64. #ifdef _AMIGA
  65. #  include <bsdsocket.h>
  66. #  define ioctl IoctlSocket
  67. #  define strcasecmp stricmp
  68. typedef long ioctl_t;
  69. typedef long sock_t;
  70. typedef long len_t;
  71. #else                   /* rudimentary unix support (untested in current version) */
  72. #  define CloseSocket close
  73. typedef int ioctl_t;
  74. typedef int sock_t;
  75. typedef int len_t;
  76. #endif
  77.  
  78. /*)) */
  79. /*(( "Global variables" */
  80.  
  81. #define MAX_HCACHESIZE 32
  82.  
  83. struct Library *SocketBase = NULL;
  84. static fd_set ReadSet;
  85. static fd_set WriteSet;
  86. static sock_t ServerSocket = -1;
  87. static int  BlockingMode;
  88. static char *ErrorTxt = NULL;              /* extended error information */
  89.  
  90. /* Struct for Hostname caching */
  91. struct HostCache {                                   /* no LRU so far... */
  92.              char Name [MAXHOSTNAMELEN];
  93.              struct in_addr Addr;
  94.          };
  95.  
  96. static struct HostCache HCache [MAX_HCACHESIZE];     /* initialised with 0s */
  97. static struct HostCache *HCacheNext = HCache;        /* next cache to be filled */
  98.  
  99.  
  100. /* This array consists only user informative errors */
  101. static char *ErrNoList[] = {
  102.     "/",                                                     /* 0 */
  103.     "Operation not permitted",             /* EPERM */
  104.     NULL,                                  /* ENOENT */
  105.     NULL,                                  /* ESRCH */
  106.     "Interrupted system call",             /* EINTR */
  107.     "Input/output error",                  /* EIO */
  108.     "Device not configured",               /* ENXIO */
  109.     NULL,                                  /* E2BIG */
  110.     NULL,                                  /* ENOEXEC */
  111.     NULL,                                  /* EBADF */
  112.     NULL,                                  /* ECHILD */      /* 10 */
  113.     "Resource deadlock avoided",           /* EDEADLK */
  114.     "Cannot allocate memory",              /* ENOMEM */
  115.     "Permission denied",                   /* EACCES */
  116.     "Bad address",                         /* EFAULT */
  117.     NULL,                                  /* ENOTBLK */
  118.     "Device busy",                         /* EBUSY */
  119.     NULL,                                  /* EEXIST */
  120.     NULL,                                  /* EXDEV */
  121.     "Operation not supported by device",   /* ENODEV */
  122.     NULL,                                  /* ENOTDIR */     /* 20 */
  123.     NULL,                                  /* EISDIR */
  124.     "Invalid argument",                    /* EINVAL */
  125.     "Too many open files in system",       /* ENFILE */
  126.     "Too many open files",                 /* EMFILE */
  127.     "Inappropriate ioctl for device",      /* ENOTTY */
  128.     NULL,                                  /* ETXTBSY */
  129.     NULL,                                  /* EFBIG */
  130.     NULL,                                  /* ENOSPC */
  131.     NULL,                                  /* ESPIPE */
  132.     NULL,                                  /* EROFS */       /* 30 */
  133.     NULL,                                  /* EMLINK */
  134.     "Broken pipe",                         /* EPIPE */
  135.     NULL,                                  /* EDOM */
  136.     NULL,                                  /* ERANGE */
  137.     "Operation would blck",                /* EAGAIN */
  138.     NULL,                                  /* EINPROGRESS */               /* <-- should be caught by handler */
  139.     "Operation already in progress",       /* EALREADY */
  140.     NULL,                                  /* ENOTSOCK */
  141.     NULL,                                  /* EDESTADDRREQ */
  142.     "Message too long",                    /* EMSGSIZE */    /* 40 */
  143.     NULL,                                  /* EPROTOTYPE */
  144.     NULL,                                  /* EPROTOOPT */
  145.     NULL,                                  /* EPROTONOSUPPORT */
  146.     NULL,                                  /* ESOCKTNOSUPPORT */
  147.     NULL,                                  /* EOPNOTSUPP */
  148.     NULL,                                  /* EPFNOSUPPORT */
  149.     NULL,                                  /* EAFNOSUPPORT */
  150.     "Address already in use",              /* EADDRINUSE */
  151.     "Can't assign requested address",      /* EADDRNOTAVAIL */
  152.     "Network is down",                     /* ENETDOWN */    /* 50 */
  153.     "Network is unreachable",              /* ENETUNREACH */
  154.     "Network dropped connection on reset", /* ENETRESET */
  155.     "Software caused connection abort",    /* ECONNABORTED */
  156.     "Connection reset by peer",            /* ECONNRESET */
  157.     "No buffer space available",           /* ENOBUFS */
  158.     NULL,                                  /* EISCONN */
  159.     NULL,                                  /* ENOTCONN */
  160.     NULL,                                  /* ESHUTDOWN */
  161.     NULL,                                  /* ETOOMANYREFS */
  162.     "Connection timed out",                /* ETIMEDOUT */   /* 60 */
  163.     "Connection refused",                  /* ECONNREFUSED */
  164.     NULL,                                  /* ELOOP */
  165.     NULL,                                  /* ENAMETOOLONG */
  166.     "Host is down",                        /* EHOSTDOWN */
  167.     "No route to host",                    /* EHOSTUNREACH */
  168.     NULL,                                  /* ENOTEMPTY */
  169.     NULL,                                  /* EPROCLIM */
  170.     NULL,                                  /* EUSERS */
  171.     NULL,                                  /* EDQUOT */
  172.     NULL,                                  /* ESTALE */      /* 70 */
  173.     NULL,                                  /* EREMOTE */
  174.     NULL,                                  /* EBADRPC */
  175.     NULL,                                  /* ERPCMISMATCH */
  176.     NULL,                                  /* EPROGUNAVAIL */
  177.     NULL,                                  /* EPROGMISMATCH */
  178.     NULL,                                  /* EPROGUNAVAIL */
  179.     NULL,                                  /* ENOLCK */
  180.     NULL,                                  /* ENOSYS */
  181.     NULL                                   /* EFTYPE */      /* 79 */
  182. };
  183.  
  184.  
  185. /*)) */
  186. static const char *amitcp_strerror (int ErrNo);
  187.  
  188. /*(( "addcache ()" */
  189.  
  190. static void addcache (const char *Name, struct in_addr Addr)
  191. {
  192.     if (strlen (Name) >= MAXHOSTNAMELEN)        /* just to be sure */
  193.     return;
  194.     debug (D_NET, ("adding cache for '%s'\n", Name));
  195.     HCacheNext->Addr = Addr;
  196.     strcpy (HCacheNext->Name, Name);
  197.     if ( ++HCacheNext >= &HCache [MAX_HCACHESIZE] )
  198.     HCacheNext = HCache;
  199. }
  200.  
  201.  
  202. /*)) */
  203. /*(( "getaddr ()" */
  204.  
  205. /* get host address by name, use cache */
  206.  
  207. static struct in_addr getaddr (const char *Name)
  208. {
  209.     struct hostent  *HostEnt;
  210.     struct in_addr r;
  211.     struct HostCache *c;
  212.  
  213.     for (c = HCache; c < &HCache [MAX_HCACHESIZE]; c++)
  214.     if (strcmp (c->Name, Name) == 0)
  215.         return (c->Addr);
  216.  
  217.     debug (D_NET, ("host '%s' not yet in cache\n", Name));
  218.     if ( (r.s_addr = inet_addr (Name)) +0 == -1)
  219.     {
  220.     if (! (HostEnt = gethostbyname (Name)) )
  221.     {
  222.         ErrorTxt = "Hostname lookup failed";
  223.         r.s_addr = (unsigned long) ~0;
  224.         return (r);
  225.     }
  226.     memmove (&r, HostEnt->h_addr, sizeof (r));
  227.     addcache (Name, *((struct in_addr *) HostEnt->h_addr));
  228.     }
  229.  
  230.     return (r);
  231. }
  232.  
  233.  
  234. /*)) */
  235. /*(( "getname ()" */
  236.  
  237. /* get host name by address, use cache */
  238. /* returns pointer to static buffer */
  239.  
  240. static const char *getname (struct in_addr Addr)
  241. {
  242.     struct hostent  *HostEnt;
  243.     struct HostCache *c;
  244.  
  245.     for (c = HCache; c < &HCache [MAX_HCACHESIZE]; c++)
  246.     if (c->Name [0] && memcmp (&c->Addr, &Addr, sizeof (Addr)) == 0)
  247.         return (c->Name);
  248.  
  249.     debug (D_NET, ("hostadr not yet in cache\n"));
  250.     if (! (HostEnt = gethostbyaddr ((caddr_t) &Addr, sizeof (struct in_addr), AF_INET)) )
  251.     return (inet_ntoa (Addr));
  252.     addcache (HostEnt->h_name, Addr);
  253.     return (HostEnt->h_name);
  254. }
  255.  
  256.  
  257. /*)) */
  258.  
  259. /*(( "init ()" */
  260.  
  261. /* Check for bsdlibrary and initialice when everything's right */
  262. /* -> Blockmode = FALSE in nonblocking mode */
  263. /* <- TRUE on success, FALSE otherwise */
  264.  
  265. static int amitcp_init (int BlockMode)
  266. {
  267.     struct servent  *ServEnt;
  268.     struct hostent  *HostEnt;
  269.     static char     LocalHostName [MAXHOSTNAMELEN];
  270.     char            *HostName;
  271.  
  272.     debug (D_NET, ("AmiTCP/IP networking module check\n"));
  273.     if (SocketBase)
  274.     return TRUE;
  275.     if (! (SocketBase = OpenLibrary ("bsdsocket.library", 2L)))
  276.     return FALSE;
  277.     debug (D_NET, ("AmiTCP/IP networking ok\n"));
  278.     SetErrnoPtr (&errno, sizeof (errno));
  279.     BlockingMode = BlockMode;
  280.  
  281.     /* get default 'http' protocoll port */
  282.     if (! (ServEnt = getservbyname ("http", "tcp")) )
  283.     syslog (LOG_WARNING, "unknown protocol 'http', using default port %d", DEFAULT_HTTPPORT);
  284.     else
  285.     {
  286.     NetAmiTCP.StdHttpPort = ServEnt->s_port;
  287.     if (NetAmiTCP.StdHttpPort != DEFAULT_HTTPPORT)
  288.         syslog (LOG_WARNING, "protocol 'http' doesn't use standard port %d", DEFAULT_HTTPPORT);
  289.     }
  290.  
  291.     /* get local hostname */
  292.     if (! (HostName = getenv ("HOSTNAME")))
  293.     syslog (LOG_ERR, "cannot get local hostname (HOSTNAME environment variable is not set)");
  294.     else
  295.     {
  296.     NetAmiTCP.HostName = HostName;
  297.     if ( (HostEnt = gethostbyname (HostName)) )
  298.     {
  299.         strncpy (LocalHostName, HostEnt->h_name, MAXHOSTNAMELEN-1);
  300.         LocalHostName [MAXHOSTNAMELEN-1] = '\0';
  301.         NetAmiTCP.HostName = LocalHostName;
  302.         free (HostName);
  303.     }
  304.     else
  305.         syslog (LOG_WARNING, "cannot resolve local hostname");
  306.     }
  307.     /*
  308.        if (gethostname (LocalHostName, MAXHOSTNAMELEN) < 0)
  309.            syslog (LOG_ERROR, "cannot get local hostname");
  310.        else
  311.        {
  312.            NetAmiTCP.HostName = LocalHostName;
  313.            if (! (HostEnt = gethostbyname (LocalHostName)))
  314.      */
  315.  
  316.     return TRUE;
  317. }
  318.  
  319. /*)) */
  320. /*(( "exit ()" */
  321.  
  322. /* exit amitcp protocol stack handler */
  323.  
  324. static void amitcp_exit (void)
  325. {
  326.     if (! SocketBase)
  327.     return;
  328.     if (ServerSocket >= 0)
  329.     CloseSocket (ServerSocket);
  330.     ServerSocket = -1;
  331.     CloseLibrary (SocketBase);
  332.     SocketBase = NULL;
  333. }
  334.  
  335. /*)) */
  336. /*(( "select ()" */
  337.  
  338. /* wait for incoming / outgoing data */
  339. /* -> onNew:   called on accepted  socket, arguemnts: new fd, calling host's name (static) */
  340. /* -> onTOut:  called at least every MIN_TIMEOUT seconds, may be more often */
  341. /* <- TRUE: received Ctrl-C - FALSE: ok or error */
  342.  
  343. static int   amitcp_select (void (*onNew)(int, const char *), void (*onTOut)(void))
  344. {
  345.     struct sockaddr_in PeerIn;
  346.     len_t  PeerLen     = sizeof (PeerIn);
  347.     sock_t Peer;
  348.     ioctl_t on = 1;
  349.     struct timeval OutTime = { MIN_TIMEOUT, 0 };
  350.  
  351.     switch (select (FD_SETSIZE, &ReadSet, &WriteSet, NULL, &OutTime))
  352.     {
  353.     case 0:
  354.     onTOut ();
  355.     return FALSE;
  356.  
  357.     case -1:
  358.     if (errno == EINTR)
  359.         return TRUE;
  360.     syslog (LOG_ERR, "select failed: %s", amitcp_strerror (errno));
  361.     return TRUE;     /* and exit... */
  362.     }
  363.  
  364.     /* Check server socket for new connections */
  365.     if (FD_ISSET (ServerSocket, &ReadSet))
  366.     {
  367.     if ( (Peer = accept (ServerSocket, (struct sockaddr *) &PeerIn, &PeerLen)) )
  368.     {
  369. #ifdef FIOASYNC
  370.         if (ioctl (Peer, FIOASYNC, (caddr_t) &on) < 0)
  371.         {
  372.         syslog (LOG_ERR, "ioctl() failed for FIOASYNC: %s", strerror (errno));
  373.         CloseSocket (Peer);
  374.         return FALSE;
  375.         }
  376. #endif
  377. #ifdef FIONBIO
  378.         if (ioctl (Peer, FIONBIO, (caddr_t) &on) < 0)
  379.         {
  380.         syslog (LOG_ERR, "ioctl() failed for FIONBIO: %s", strerror (errno));
  381.         CloseSocket (Peer);
  382.         return FALSE;
  383.         }
  384. #endif
  385.         /* look up hostname here */
  386.         onNew ((int) Peer, getname (PeerIn.sin_addr));
  387.     }
  388.     else
  389.         syslog (LOG_ERR, "accept() failed: %s", strerror (errno));
  390.     }
  391.  
  392.     return FALSE;
  393. }
  394.  
  395. /*)) */
  396. /*(( "checkread/write ()" */
  397.  
  398. static int   amitcp_checkread (int Fd)
  399. {
  400.     return (FD_ISSET (Fd, & ReadSet));
  401. }
  402.  
  403. static int   amitcp_checkwrite (int Fd)
  404. {
  405.     return (FD_ISSET (Fd, & WriteSet));
  406. }
  407.  
  408. /*)) */
  409. /*(( "read/write ()" */
  410.  
  411. static int amitcp_read (int Fd, char *Buffer, int Size)
  412. {
  413.     int   i;
  414.     if ( (i = recv ((sock_t) Fd, Buffer, (len_t) Size, 0)) < 0)
  415.     ErrorTxt = "Read failed";
  416.     return i;
  417. }
  418.  
  419. static int amitcp_write (int Fd, char *Buffer, int Size)
  420. {
  421.     int   i;
  422.     if ( (i = send ((sock_t) Fd, Buffer, (len_t) Size, 0)) < 0)
  423.     ErrorTxt = "Write failed";
  424.     return i;
  425. }
  426.  
  427. /*)) */
  428. /*(( "server ()" */
  429.  
  430. /* open and set up server socket */
  431.  
  432. static int amitcp_server (int Port)
  433. {
  434.     struct sockaddr_in SockIn;
  435.     ioctl_t on = 1;
  436.  
  437.     if (ServerSocket)
  438.     CloseSocket (ServerSocket);
  439.     if ( (ServerSocket = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  440.     {
  441.     ErrorTxt = "socket() for serverport failed";
  442.     return FALSE;
  443.     }
  444.  
  445.     memset ((char *) &SockIn, 0, sizeof (struct sockaddr_in));
  446.     SockIn.sin_family      = AF_INET;
  447.     SockIn.sin_addr.s_addr = INADDR_ANY;
  448.     SockIn.sin_port        = htons (Port);
  449.     if (bind (ServerSocket, (struct sockaddr *) &SockIn, sizeof (struct sockaddr_in)) < 0)
  450.     {
  451.     ErrorTxt = "bind() failed for serverport";
  452.     return FALSE;
  453.     }
  454.  
  455.     if (! BlockingMode)
  456.     {
  457. #ifdef FIOASYNC
  458.     if (ioctl (ServerSocket, FIOASYNC, (caddr_t) &on) < 0)
  459.     {
  460.         ErrorTxt = "ioctl() failed for FIOASYNC";
  461.         return FALSE;
  462.     }
  463. #endif
  464. #ifdef FIONBIO
  465.     if (ioctl (ServerSocket, FIONBIO, (caddr_t) &on) < 0)
  466.     {
  467.         ErrorTxt = "ioctl() failed for FIONBIO";
  468.         return FALSE;
  469.     }
  470. #endif
  471.     }
  472.  
  473.     if (listen (ServerSocket, 5) < 0)
  474.     {
  475.     ErrorTxt = "listen() failed";
  476.     return FALSE;
  477.     }
  478.  
  479.     return TRUE;
  480. }
  481.  
  482. /*)) */
  483. /*(( "open ()" */
  484.  
  485. /* open and set up server socket */
  486. /* <- -1: error  Fd: otherwise */
  487.  
  488. static int amitcp_open (const char *Host, int Port)
  489. {
  490.     struct sockaddr_in SockIn;
  491.     ioctl_t on = 1;
  492.     sock_t Sock;
  493.  
  494.     memset ((char *) &SockIn, 0, sizeof (struct sockaddr_in));
  495.     SockIn.sin_family      = AF_INET;
  496.     SockIn.sin_port        = htons (Port);
  497.     if ( (SockIn.sin_addr  = getaddr (Host)).s_addr == ~0)
  498.     return -1;
  499.  
  500.     if ( (Sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
  501.     {
  502.     ErrorTxt = "socket() failed";
  503.     return -1;
  504.     }
  505.  
  506.     if (! BlockingMode)
  507.     {
  508. #ifdef FIOASYNC
  509.     if (ioctl (Sock, FIOASYNC, (caddr_t) &on) < 0)
  510.     {
  511.         ErrorTxt = "ioctl() failed for FIOASYNC";
  512.         CloseSocket (Sock);
  513.         return -1;
  514.     }
  515. #endif
  516. #ifdef FIONBIO
  517.     if (ioctl (Sock, FIONBIO, (caddr_t) &on) < 0)
  518.     {
  519.         ErrorTxt = "ioctl() failed for FIONBIO";
  520.         CloseSocket (Sock);
  521.         return -1;
  522.     }
  523. #endif
  524.     }
  525.  
  526.     if (connect (Sock, (struct sockaddr *) &SockIn, sizeof (struct sockaddr_in)) < 0)
  527.     if (errno != EINPROGRESS)
  528.     {
  529.         ErrorTxt = "connect() failed";
  530.         CloseSocket (Sock);
  531.         return -1;
  532.     }
  533.  
  534.     errno = 0;
  535.     return Sock;
  536. }
  537.  
  538. /*)) */
  539. /*(( "close ()" */
  540.  
  541. /* open and set up server socket */
  542.  
  543. static void amitcp_close (int Fd)
  544. {
  545.     CloseSocket ((sock_t) Fd);
  546. }
  547.  
  548. /*)) */
  549. /*(( "initfd/setfdread/write ()" */
  550.  
  551. /* <- Server: accept incoming requests */
  552.  
  553. static void amitcp_initfd (int Server)
  554. {
  555.     FD_ZERO (& ReadSet);
  556.     FD_ZERO (& WriteSet);
  557.     if (Server)
  558.     FD_SET  (ServerSocket, & ReadSet);
  559. }
  560.  
  561. static void amitcp_setfdread (int Fd)
  562. {
  563.     FD_SET  ((sock_t) Fd, &ReadSet);
  564. }
  565.  
  566. static void amitcp_setfdwrite (int Fd)
  567. {
  568.     FD_SET  ((sock_t) Fd, &WriteSet);
  569. }
  570.  
  571. /*)) */
  572. /*(( "strerror ()" */
  573.  
  574. /* return enhanced error string */
  575.  
  576. static const char *amitcp_strerror (int ErrNo)
  577. {
  578.     static char Err [128];
  579.     char   *c;
  580.  
  581.     if (ErrorTxt)
  582.     {
  583.     sprintf (Err, "%s: ", ErrorTxt);
  584.     c = Err + strlen (Err);
  585.     sprintf (c, (ErrNo < sizeof(ErrNoList) / sizeof(ErrNoList[0]) && ErrNo >= 0 && ErrNoList [ErrNo]) ? ErrNoList [ErrNo] : "Error #%d", ErrNo);
  586.     ErrorTxt = NULL;
  587.     }
  588.     else
  589.     sprintf (Err, (ErrNo < sizeof(ErrNoList) / sizeof(ErrNoList[0]) && ErrNo >= 0 && ErrNoList [ErrNo]) ? ErrNoList [ErrNo] : "Error #%d", ErrNo);
  590.  
  591.     return (Err);
  592. }
  593.  
  594. /*)) */
  595. /*(( "Method dispatch table" */
  596.  
  597. netmethods_t NetAmiTCP = {
  598.                 "AmiTCP V2.2",
  599.                 "unknown",
  600.                 FD_SETSIZE,
  601.                 DEFAULT_HTTPPORT,
  602.                 amitcp_init,
  603.                 amitcp_exit,
  604.                 amitcp_select,
  605.                 amitcp_checkread,
  606.                 amitcp_checkwrite,
  607.                 amitcp_read,
  608.                 amitcp_write,
  609.                 amitcp_server,
  610.                 amitcp_open,
  611.                 amitcp_close,
  612.                 amitcp_initfd,
  613.                 amitcp_setfdread,
  614.                 amitcp_setfdwrite,
  615.                 amitcp_strerror
  616.              };
  617.  
  618. /*)) */
  619.  
  620.